<?php
/**
 * File.php
 * Notes:
 * author: chen
 * DateTime: 2022/1/25 17:17
 * @package Xtsb\Cims\File
 */

namespace Xtsb\Cims\File;


use Xtsb\Cims\Audit\ApmCodeTable;
use Xtsb\Cims\Exception\ApiErrorDesc;
use Xtsb\Cims\Exception\ApiException;
use think\facade\Db;

class File
{
  /**
   * Notes:文件转base64输出
   * author: chen
   * DateTime: 2022/1/25 17:17
   * @param string $image_file
   * @return string
   */
  public static function fileToBase64($filename = 'test/工程文件/【202101】2021年三季度驻马店市区/合同文件/test.docx')
  {

    $fileBase64 = fread(fopen($filename, 'r'), filesize($filename));
    $Base64Type = 'data:' . mime_content_type($filename) . ';base64,';
    $fileData = $Base64Type . base64_encode($fileBase64);
    return $fileData;
  }

  /**
   * base64转文件输出
   * @param String $base64_data base64数据
   * @param String $filename 要保存的文件路径
   * @return boolean
   */
  public static function base64ToFile($base64Data, $filename)
  {
    if (!$base64Data || !$filename) {
      return false;
    }
    return file_put_contents($filename, base64_decode($base64Data), true);
  }

  function imgBase64ToFile($filePath, $base64Data)
  {
    /* 通过正则匹配得到 base64 头信息和图片信息等 */
    $pregInfo = preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64Data, $photoInfo);
    $result = false;
    /* 匹配到结果则开始处理 */
    if ($pregInfo != false) {
      /* 去除base64头：data:image/jpeg;base64,这部分的内容需要去掉，不然 base64_decode 出来的图片是损坏的 */
      $clearBase64HeadWithPhoto = str_replace($photoInfo[1], '', $base64Data);
      $clearBase64HeadWithPhoto = str_replace(' ', '+', $clearBase64HeadWithPhoto);
      /* base64_decode base64编码，重新得到图片的内容 */
      $photoFileSource = base64_decode($clearBase64HeadWithPhoto);
      /* 写文件 */
      $file = file_put_contents($filePath, $photoFileSource);
    }

    return $file;
  }

  public static function getDirname($dirname = null, $is_uid = false, $subDir = null, $cuid = null)
  {
    if (isset($cuid) && !defined('CUACCOUNT')) {
      $cuInfo = Db::name('company')->field('account,ip')->where('id', $cuid)->find();
      define('CUACCOUNT', $cuInfo['account']);
    }
    if (isset($dirname)) {
      return CUACCOUNT . '/' . $dirname;
    }
    $table_name = input('table_name', get_table_name());

    if ($is_uid) {
      $dir_name = CUACCOUNT . '/temp/' . $table_name . '/UID_' . UID . ($subDir ? ('_' . $subDir) : '');
    } else {
      $dir_name = CUACCOUNT . '/temp/' . $table_name . '/' . uniqid() . rand(10000, 99999);
    }
    return $dir_name;
  }

  /**
   * @param null $dirname
   * @param null $cuid
   * @return false|string
   */
  public static function getDirnameNew($dirname = null, $cuid = null)
  {
    $cuInfo = Db::name('company')->field('account,ip')->where('id', $cuid)->find();
    $cuaccount = $cuInfo['account'];
    if (empty($cuaccount)) {
      return false;
    }
    if (isset($dirname)) {
      return $cuaccount . '/' . $dirname;
    }
    $table_name = input('table_name', get_table_name());
    $dir_name = $cuaccount . '/temp/' . $table_name . '/' . uniqid() . rand(10000, 99999);
    return $dir_name;
  }

  /**
   * Notes:生成app端施工队文件目录
   * author: chen
   * DateTime: 2022/11/16 16:07
   * @param null $dirname 已知目录结构则传入
   * @param null $subDir
   * @return string
   */
  public static function getWorkerDirname($cuid, $dirname = null, $subDir = null)
  {
    if (!isset($cuid)) {
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, 'cuid不能为空');
    }
    $comInfo = Db::name('company')->field('account,ip')->where('id', $cuid)->find();

    if (isset($dirname)) {
      return $comInfo['account'] . '/' . $dirname;
    }

    $dirname = $comInfo['account'] . '/worker/' . get_table_name() . '/WID_' . WID . ($subDir ? ('_' . $subDir) : '');

    return $dirname;
  }

  /**
   * Notes: 生成app端施工队文件HOST
   * author: chen
   * DateTime: 2022/11/16 16:21
   * @param $cuid int 企业id
   * @return mixed|string
   */
  public static function getWorkerImageIp($cuid)
  {
    if (!isset($cuid)) {
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, 'cuid不能为空');
    }
    $comInfo = Db::name('company')->field('account,ip')->where('id', $cuid)->find();

    if (!$comInfo) {
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '企业不存在');
    }

    if ($comInfo['ip']) {
      return config('app.image_domain') . $comInfo['ip'];
    }

    return config('app.image_domain') . config('app.image_ip');
  }


  /**
   * Notes: 变更目录名称
   * author: lizhongjie
   * DateTime: 2022/11/3 11:40
   * @param $id int
   * @param $dirname array
   * @param $act_table_name string  可能目录会分布到多个不同数据表，因此需要传入参数来指定
   * @throws \think\db\exception\DbException
   */
  public static function changeDirname($id, &$dirname, $act_table_name = null)
  {
    if (empty($dirname)) {
      return;
    }

    $new_dirname = [];
    if ($act_table_name) {
      $table_name = $act_table_name;
    } else {
      $table_name = input('table_name', get_table_name());
      $act_table_name = ApmCodeTable::getTableName($table_name) ?? $table_name;
    }
    empty($table_name) and $table_name = $act_table_name;
    if (empty($table_name))
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件目录需要临时适配，请联系平台客服');

    if (is_array($dirname) && isset($dirname[0])) {
      foreach ($dirname as $key => $item) {
        $new_dirname[$key]['old_dirname'] = $item['dirname'];
        $new_dirname[$key]['new_dirname'] = $item['title'];
      }
      $result = self::mkDirAndMoveFile($new_dirname, $table_name . '/' . uniqid() . rand(10000, 99999), 'temp');//移动目录

      if (key_exists('code', $result) && $result['code'] == 0) {
        $new_dirname = $result['data'];
        foreach ($dirname as $_key => $_value) {
          $data['dirname'][$_key]['title'] = $_value['title'];
          $data['dirname'][$_key]['dirname'] = $new_dirname[$_key];
        }
        if (!empty($data['dirname'])) {
          Db::name($act_table_name)->where('id', $id)->json(['dirname'])->update($data);
          $dirname = $data['dirname'];//可能需要返回数据，直接对传参进行数据变更
        }
      }

    } else if (is_string($dirname)) {
      $filename = null;
      if (strpos($dirname, '.') != false) {
        $filename = basename($dirname);
        $dirname = str_replace($filename, '', $dirname);
      }

      $new_dirname[0]['old_dirname'] = $dirname;
      $new_dirname[0]['new_dirname'] = '';
      $result = self::mkDirAndMoveFile($new_dirname, $table_name . '/' . uniqid() . rand(10000, 99999), 'temp');//移动目录
      if (key_exists('code', $result) && $result['code'] == 0) {
        if (isset($filename)) {
          $data['dirname'] = $result['data'][0] . $filename;
        } else {
          $data['dirname'] = $result['data'][0];
        }
        Db::name($act_table_name)->where('id', $id)->update($data);
        $dirname = $result['data'][0];//可能需要返回数据，直接对传参进行数据变更
      }
    } else {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '模块目录不正确');
    }

    $count = Db::name($act_table_name)->where('id', $id)->whereLike('dirname', '%UID%')->count();
    if ($count)
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '服务器缓存目录移动失败，可能是网络问题导致。请您再次提交，若连续多次提交失败，请联系平台客服');
  }

  /**
   * Notes: 变更目录名称
   * author: lizhongjie
   * DateTime: 2022/11/3 11:40
   * @param $id int
   * @param $dirname array
   * @param $act_table_name string  可能目录会分布到多个不同数据表，因此需要传入参数来指定
   * @throws \think\db\exception\DbException
   */
  public static function changeWorkerDirname($id, &$dirname, $act_table_name = null, $cuid = null)
  {
    if (empty($dirname))
      return;
    $new_dirname = [];
    $table_name = input('table_name', get_table_name());
    $act_table_name = $act_table_name ?? ApmCodeTable::getTableName($table_name) ?? $table_name;
    if (is_array($dirname) && isset($dirname[0])) {
      foreach ($dirname as $key => $item) {
        $new_dirname[$key]['old_dirname'] = $item['dirname'];
        $new_dirname[$key]['new_dirname'] = $item['title'];
      }
      $result = self::mkWorkerDirAndMoveFile(
        $new_dirname,
        $table_name . '/' . uniqid() . rand(10000, 99999),
        'temp',
        $cuid
      );//移动目录

      if (key_exists('code', $result) && $result['code'] == 0) {
        $new_dirname = $result['data'];
        foreach ($dirname as $_key => $_value) {
          $data['dirname'][$_key]['title'] = $_value['title'];
          $data['dirname'][$_key]['dirname'] = $new_dirname[$_key];
        }
        Db::name($act_table_name)->where('id', $id)->json(['dirname'])->update($data);
        $dirname = $data['dirname'];//可能需要返回数据，直接对传参进行数据变更
      }
    } else if (is_string($dirname)) {
      $new_dirname[0]['old_dirname'] = $dirname;
      $new_dirname[0]['new_dirname'] = '';
      $result = self::mkWorkerDirAndMoveFile(
        $new_dirname,
        $table_name . '/' . uniqid() . rand(10000, 99999),
        'temp',
        $cuid
      );//移动目录
      if (key_exists('code', $result) && $result['code'] == 0) {
        Db::name($act_table_name)->where('id', $id)->json(['dirname'])->update(['dirname' => $result['data'][0]]);
        $dirname = $result['data'][0];//可能需要返回数据，直接对传参进行数据变更
      }
    } else {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '模块目录不正确');
    }
  }

  /**
   * @param string $dirName 文件主目录名称
   * @param string $sub_dirname 文件子目录名称
   * @param string $fileTypeName 文件分类目录名
   */
  public static function mkDirAndMoveFile($dirNames = [], $sub_dirname = null, $fileTypeName = '工程文件')
  {
    if (empty($dirNames)) {
      return true;
    }
//    $main_path = CUACCOUNT;
//    if (!empty($fileTypeName)) {
//      $main_path .= '/' . $fileTypeName;
//    }

    foreach ($dirNames as $key => $dirName) {
      $filepath = '';
      if (strpos($dirName['new_dirname'], CUACCOUNT) === false) {
        //不存在企业账号 则拼接
        $filepath .= CUACCOUNT . '/';
      }
      if (!empty($fileTypeName)) {
        //子目录不为空 则拼接
        $filepath .= $fileTypeName . '/';
      }
      if (!empty($sub_dirname)) {
        //子目录不为空 则拼接
        $filepath .= $sub_dirname . '/';
      }
      $dirNames[$key]['new_dirname'] = !empty($filepath) ? ($filepath . $dirName['new_dirname']) : $dirName['new_dirname'];
    }

    $data['dirname'] = $dirNames;

    $http = new Http();
    $result = (array)$http->setHost(get_image_ip_addr())->setApi('/moveFileToNewDir')->post($data);

    return $result;
  }

  public static function moveFile($dirNames = [], $sub_dirname = null, $fileTypeName = '工程文件')
  {
    if (empty($dirNames)) {
      return true;
    }
    $data['dirname'] = $dirNames;
    $http = new Http();

    $result = (array)$http->setHost(get_image_ip_addr())->setApi('/moveFileToNewDir')->post($data);
    return $result;
  }

  /**
   * @param array $dirName 文件主目录名称
   * @param null $sub_dirname 文件子目录名称
   * @param string $fileTypeName 文件分类目录名
   * @param null $cuid
   * @return array|bool
   * @throws \think\db\exception\DataNotFoundException
   * @throws \think\db\exception\DbException
   * @throws \think\db\exception\ModelNotFoundException
   */
  public static function mkWorkerDirAndMoveFile($dirNames = [], $sub_dirname = null, $fileTypeName = '工程文件', $cuid = null)
  {
    if (empty($dirNames)) {
      return true;
    }
    if ($cuid) {
      $comInfo = Db::name('company')->field('account,ip')->where('id', $cuid)->find();
      $account = $comInfo['account'];
    } else {
      $account = CUACCOUNT;
    }

    $main_path = $account . '/' . $fileTypeName;

    foreach ($dirNames as $key => $dirName) {
      $dirNames[$key]['new_dirname'] = $main_path . '/' . $sub_dirname . '/' . $dirName['new_dirname'];
    }

    $data['dirname'] = $dirNames;

    $http = new Http();
    $result = (array)$http->setHost(get_worker_image_ip_addr($cuid))->setApi('/moveFileToNewDir')->post($data);

    return $result;
  }

  /**
   * 删除文件目录及其下文件
   * @param $dirName
   * @return bool
   */
  public static function delDirAndFile($dirName, $ip = null)
  {
    if (!$dirName) {
      return true;
    }
    $host = get_image_ip_addr($ip);
    $data['dirname'] = self::getDirnameFromPath($dirName);

    $http = new Http();
    $result = $http->setHost($host)->setApi('/delDirAndFile')->post($data);

    if (!$result || (isset($result['code']) && $result['code'])) {
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件删除失败，请联系管理员');
    }

    return $result;
  }

  public static function delFile($filepath, $ip = null)
  {
    if (!$filepath) {
      return true;
    }
    $host = get_image_ip_addr($ip);
    $data['filename'] = $filepath;
    $http = new Http();
    $result = $http->setHost($host)->setApi('/delFile')->post($data);

    if (!$result || (isset($result['code']) && $result['code'])) {
      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件删除失败，请联系管理员');
    }

    return $result;
  }

  /**
   * 获取文件
   */
  /**
   * Notes:
   * author: chen
   * DateTime: 2022/12/15 17:08
   * @param $dirName
   * @param null $ip
   * @param null $fileType 返回的文件类型 file 返回地址 base64 返回base64字符串
   * @return array|mixed|string
   */
  public static function getFile($dirName, $ip = null, $fileType = null, $msg = '合同文件不存在，请联系管理员', $err = true)
  {
    try {
      if (!$dirName) {
        return [];
      }
      $host = get_image_ip_addr($ip);

      $data['dirname'] = self::getDirnameFromPath($dirName);

      $http = new Http();
      $result = $http->setHost($host)->setApi('/get-file')->post($data);

      if (!$result || $result['code'] || empty($result['data'])) {
        if ($err) {
          throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $msg);
        } else {
          return false;
        }
      } else {
        $files = array_map(function ($item) use ($dirName, $fileType) {
          $files = explode('|', $item);//切割文件名称信息
          if ($fileType == 'file') {
            if (strpos($dirName, '.') != false) {
              return $dirName;
            } else {
              return $dirName . '/' . $files[0];
            }
          } else if ($fileType == 'base64') {
            return $files[1];
          } else {
            return $item;
          }
        }, $result['data']);

        if (empty($files) && $err) {
          throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $msg);
        }

        return $files;
      }

    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }

  /**
   * 上传文件
   */
  public static function postFile($filename, $dirName, $ip = null, $fileType = 'file')
  {
    try {
      if (!$dirName) {
        return [];
      }

      if (is_file('.' . $filename)) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件不存在：' . $filename);
      }

      $host = get_image_ip_addr($ip);

      $http = new Http();
      $result = $http->setHost($host)->setApi('/upload')->postFile($filename, $dirName);

      if (!$result || $result['code']) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件上传失败，请联系管理员');
      }

      $files = array_map(function ($item) use ($dirName, $fileType) {
        $files = explode('|', $item);//切割文件名称信息
        if ($fileType == 'file') {
          if (strpos($dirName, '.') != false) {
            return $dirName;
          } else {
            return $dirName . '/' . $files[0];
          }
        } else if ($fileType == 'base64') {
          return $files[1];
        } else {
          return $item;
        }
      }, $result['data']);

      if (empty($files)) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '文件上传失败，请联系管理员');
      }

      return $files;
    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }

  /**
   * 文件压缩
   * @param $data {"zip_name":"","dirnames":[{"zip_dirname":"","current_dirname":""}],"watermark_text":""}
   * @param $zip_name string 压缩文件名称
   * @param $dirnames array 压缩：源目录=>目标目录
   * @param $watermark_text string 水印
   * @param $ip
   * @return mixed
   */
  public static function zip($data, $ip = null)
  {
    try {
      if (empty($data)) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '压缩目录为空');
      }

      $host = get_image_ip_addr($ip);

      $http = new Http();
      $result = $http->setHost($host)->setApi('/zip/create')->post($data);

      if (!$result || $result['code']) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $result['msg'] ?? '文件压缩失败，请联系管理员');
      }

      return $result['data'];
    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }

  // 文件打包下载
  public static function zipDownload($data, $ip = null)
  {
    try {
      if (empty($data)) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '批量下载文件不能为空');
      }

      $host = get_image_ip_addr($ip);

      $http = new Http();

      $result = $http->setHost($host)->setApi('/zip/download')->post($data);

      if (!$result || $result['code']) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $result['msg'] ?? '文件批量下载失败，请联系管理员');
      }

      return $result['data'];
    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }

  /**
   * Notes:获取文件地址中的目录部分
   * author: chen
   * DateTime: 2023/1/5 20:34
   */
  public static function getDirnameFromPath($dirname)
  {
    if (strpos($dirname, '.') != false) {
      $filename = basename($dirname);
      $dirname = str_replace($filename, '', $dirname);
    }
    return $dirname;
  }


  /**
   * 获取目录下的文件列表
   * @param $dirName
   * @param null $ip
   * @return array|bool|mixed|string
   */
  public static function fileListByDirname($dirName, $ip = null)
  {
    try {
      if (!$dirName) {
        return [];
      }
      $host = get_image_ip_addr($ip);

      $data['dirname'] = $dirName;

      $http = new Http();
      $result = $http->setHost($host)->setApi('/dirFileList')->post($data);

      if (!$result || $result['code'] || empty($result['data'])) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '目录不存在，请联系管理员');
      } else {

        return $result;
      }

    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }


  /**
   * 获取文件信息
   * @param array $dirName
   * @param null $ip
   * @return array|bool|mixed|string
   */
  public static function fileInfo(array $dirNames, $ip = null)
  {
    try {
      if (!$dirNames) {
        return [];
      }
      $host = get_image_ip_addr($ip);

      $data['dirname'] = $dirNames;

      $http = new Http();
      $result = $http->setHost($host)->setApi('/file-info')->post($data);

      if (!$result || $result['code'] || empty($result['data'])) {
        throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, '目录不存在，请联系管理员');
      } else {

        return $result;
      }

    } catch (\Exception $exception) {

      throw new ApiException(ApiErrorDesc::ERROR_DEFAULT, $exception->getMessage());
    }
  }

  /**
   * 获取文件url地址
   * @param string $filePath
   * @param null $ip
   */
  public static function getFileUrl($filePath, $ip = null)
  {
    $host = get_image_ip_addr($ip);
    return $host . '/' . $filePath;
  }

  /**
   * 远程文件是否存在
   * @param $filePath
   * @param $ip
   */
  public static function existRemoteFile($filePath, $ip = null)
  {
    if (empty($filePath)) {
      return false;
    }
    $fileUrl = self::getFileUrl($filePath, $ip);
    if (empty($fileUrl)) {
      return false;
    }

    try {
      $files = self::getFile($filePath, $ip, 'file', '文件不存在');
    } catch (\Exception $e) {
      return false;
    }

    if (!empty($files)) {
      return true;
    }

    return false;
  }


  /**
   * 删除文件夹(递归)
   * @param $directory
   */
  public static function rmDirAllForLocal($directory, $isForce = false)
  {
    if (is_dir($directory)) { // 判断是否为目录
      $files = scandir($directory); // 获取目录下的所有文件和文件夹（包括"."和".."）
      if ($isForce) {
        foreach ($files as $file) {
          if ($file != "." && $file != "..") { // 跳过当前目录和上级目录
            $path = "$directory/$file"; // 构建完整路径

            if (is_file($path)) { // 若是文件，则直接删除
              unlink($path);
            } elseif (is_dir($path)) { // 若是目录，则进行递归调用
              self::rmDirAllForLocal($path, true);
            }
          }
        }
      }
      @rmdir($directory); // 最后删除空的目录
    }
  }
}
